/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _TRI_MD2MODEL_H__
#define _TRI_MD2MODEL_H__

#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <fstream>

//Include library header
#include "entity.h"

using namespace std;


namespace tri{


// OpenGL vector types
typedef GLfloat vec2_t[2];
typedef GLfloat vec3_t[3];


// Md2 header
struct Md2Header_t
{
  int ident;          // Magic number, "IDP2"
  int version;        // Md2 format version, should be 8

  int skinwidth;      // Texture width
  int skinheight;     // Texture height

  int framesize;      // Size of a frame, in bytes

  int num_skins;      // Number of skins
  int num_vertices;   // Number of vertices per frame
  int num_st;         // Number of texture coords
  int num_tris;       // Number of triangles
  int num_glcmds;     // Number of OpenGL commands
  int num_frames;     // Number of frames

  int offset_skins;   // offset to skin data
  int offset_st;      // offset to texture coords
  int offset_tris;    // offset to triangle data
  int offset_frames;  // offset to frame data
  int offset_glcmds;  // offset to OpenGL commands
  int offset_end;     // offset to the end of the file
};


// Skin data
struct Md2Skin_t
{
  char name[64];  // Texture's filename
};


// Texture coords.
struct Md2TexCoord_t
{
  short s;
  short t;
};


// Triangle data
struct Md2Triangle_t
{
  unsigned short vertex[3];  // Triangle's vertex indices
  unsigned short st[3];      // Texture coords. indices
};


// Vertex data
struct Md2Vertex_t
{
  unsigned char v[3];         // Compressed vertex position
  unsigned char normalIndex;  // Normal vector index
};


// Frame data
struct Md2Frame_t
{
  // Destructor
  ~Md2Frame_t () {
    delete [] verts;
  }

  vec3_t scale;        // Scale factors
  vec3_t translate;    // Translation vector
  char name[16];       // Frame name
  Md2Vertex_t *verts;  // Frames's vertex list
};


// OpenGL command packet
struct Md2Glcmd_t
{
  float s;    // S texture coord.
  float t;    // T texture coord.
  int index;  // Vertex index
};


// Animation infos
struct Md2Anim_t
{
  int start;  // first frame index
  int end;    // last frame index
};

typedef Md2Anim_t TMd2AnimInfo;

/**
 * MD2 Model Entity
 * @see http://tfc.duke.free.fr/old/models/md2.htm
 */
class TMD2Model : public tri::TEntity{

public:
    // Internal types
    typedef std::map<string, tri::TTexture*> SkinMap;
    typedef std::map<string, Md2Anim_t> AnimMap;

	TMD2Model();
	virtual ~TMD2Model();
	
	int load(std::string filename);
	virtual void display();
	virtual void update();
	void clear();
	
    void renderFrameImmediate (int frame);
    void drawModelItpImmediate (int frameA, int frameB, float interp);

    void renderFrameWithGLcmds (int frame);
    void drawModelItpWithGLcmds (int frameA, int frameB, float interp);

    void setScale (GLfloat scale) { _scale = scale; }
    
    void getAnimationList(std::vector<std::string>& list );
    TMd2AnimInfo getAnimationInfo(std::string anim);
    
    void setAnimation(std::string ani, float fps, bool loop = true);
    std::string getAnimation();

    bool isAnimating(){return mAnimating;}
    // Accessors
    const SkinMap &skins () const { return _skinIds; }
    const AnimMap &anims () const { return _anims; }
    
    void setOffsetPosition(tri::TVector);
	void setOffsetRotation(tri::TVector);
    
    int m_CurrentFrame;
    int m_NextFrame;
    float m_FrameProgress;
    bool m_LoopAnimation;
    std::string m_CurrentAnimation;
    bool mAnimating;
	
private:
    bool hasAnimation(std::string);

    void setupAnimations();
  // Constants
  
  static int _kMd2Ident;
  static int _kMd2Version;
  tri::TTexture* _tex;
  
  // Model data
  Md2Header_t _header;
  Md2Skin_t *_skins;
  Md2TexCoord_t *_texCoords;
  Md2Triangle_t *_triangles;
  Md2Frame_t *_frames;
  int *_glcmds;
  static vec3_t _kAnorms[162];

  GLfloat _scale;
  
  SkinMap _skinIds;
  AnimMap _anims;
  tri::TProgressTimer mTimer;
  
  tri::TVector mOffsetPosition;
  tri::TVector mOffsetRotation;
	
};

}
#endif
